package com.example.uploadingfiles;

import java.io.IOException;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.example.uploadingfiles.storage.StorageFileNotFoundException;
import com.example.uploadingfiles.storage.StorageService;

/**
 * 文件上传控制器
 */
@Controller
public class FileUploadController {

    private final StorageService storageService;

    /**
     * 文件上传控制器(类方法)
     * @param storageService : 存储服务接口
     */
    @Autowired
    public FileUploadController (StorageService storageService) {
        this.storageService = storageService;
    }

    /**
     * 上传文件列表
     * @param model :向模型添加属性
     * @return ： 视图
     * @throws IOException : 异常
     */
    @GetMapping("/")
    public String listUploadedFiles (Model model) throws IOException {
        model.addAttribute("files", storageService.loadAll()
                .map(path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class, "serveFile", path.getFileName().toString()).build().toUri().toString())
                .collect(Collectors.toList()));
        return "uploadForm";
    }

    /**
     * 保存文件
     * @param filename ： 文件名
     * @return ：请求实体
     */
    @GetMapping("/files/{filename:.+}")
    @ResponseBody
    public ResponseEntity<Resource> serveFile (@PathVariable String filename) {

        Resource file = storageService.loadAsResource(filename);
        return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
    }

    /**
     * 处理文件上传
     * @param file : 在多部分请求中接收到的上传文件的表示形式
     * @param redirectAttributes : Model接口的专门化，控制器可以使用它为重定向场景选择属性
     * @return
     */
    @PostMapping("/")
    public String handleFileUpload (@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {

        storageService.store(file);
        redirectAttributes.addFlashAttribute("message", "You successfully uploaded " + file.getOriginalFilename() + "!");

        return "redirect:/";
    }

    /**
     * 处理存储文件未找到
     * @param exc : 异常处理类
     * @return : 请求实体
     */
    @ExceptionHandler(StorageFileNotFoundException.class)
    public ResponseEntity<?> handleStorageFileNotFound (StorageFileNotFoundException exc){
        return ResponseEntity.notFound().build();
    }
}
